#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include "../list/GenericList.h"
#include <stdlib.h>
#include "../decompressor/ZipFileDecompressor.h"
using namespace std;

    //    ZipFileDecompressor(FILE* file) : file_(file)
    //    {
    //        headersInfo_ = navigate();
    //    }

    ZipFileDecompressor::ZipFileDecompressor(const char* filePath, const char* destinyPath)
    {
        file_ = fopen(filePath, "rb");
        headersInfo_ = navigate();
        destinyPath_ = (char*) malloc(strlen(destinyPath) + 1);
        strcpy(destinyPath_, destinyPath);
    }

    ZipFileDecompressor::~ZipFileDecompressor()
    {
        free(destinyPath_);
    }

    FILE* ZipFileDecompressor::createFile(char* fileName)
    {
        return fopen(fileName, "wb");
    }

    void ZipFileDecompressor::putFileContent(FILE* file, char* fileData)
    {
        fwrite(fileData, 1, strlen(fileData), file);
        fclose(file);
    }

    void ZipFileDecompressor::createDirectory(const char* pathName)
    {

        int createDir = mkdir(pathName, S_IRWXU | S_IRGRP | S_IXGRP);
        if (createDir < 0)
        {
            perror("mkdir error\n");
        } else
        {
            printf("directory created succesfully\n");
        }

    }

    void ZipFileDecompressor::decompress()
    {
        FileHeaderInfo* fileHeader = 0;
        for (int i = 0; i < headersInfo_.size(); i++)
        {
            fileHeader = headersInfo_.get(i);
            char* destinyPath = (char*) malloc(strlen(destinyPath_) + strlen(fileHeader->fileFullPathName_) + 1);

//#ifdef WIN32
            sprintf(destinyPath, "%s%s", destinyPath_, fileHeader->fileFullPathName_);
//#else
//            sprintf(destinyPath, "%s/%s", destinyPath_, fileHeader->fileFullPathName_);
//#endif 
            if (fileHeader->fileFullPathName_[fileHeader->size_ - 1] == '/')
            {
                createDirectory(destinyPath);

            }
            else
            {
                putFileContent(createFile(destinyPath), fileHeader->fileData_);
            }
            free(destinyPath);
        }
    }

    GenericList<FileHeaderInfo*> ZipFileDecompressor::navigate()
    {
        GenericList<FileHeaderInfo*> fileHeadersList;
        int header;
        short versionToExtract;
        short size;
        short flag = 0;

        short compressedMethod;
        unsigned short date;
        unsigned short time;
        unsigned int dateTime;
        short extraFieldLength = 0;
        int compressedSize = 0;
        int unCompressedSize;
        int count = 0;
        int crc;
        char * fileBuffer;

        while (!feof(file_))
        {
            fread(&header, sizeof (header), 1, file_); // Read the header to know if is a file
            if (header == 67324752) //To know if is a file header
            {
                fread(&versionToExtract, sizeof (versionToExtract), 1, file_);
                fread(&flag, sizeof (flag), 1, file_); // read the flag
                fread(&compressedMethod, sizeof (compressedMethod), 1, file_); //read the compression method
                fread(&time, sizeof (time), 1, file_);
                fread(&date, sizeof (date), 1, file_);
                fread(&crc, sizeof (crc), 1, file_); // read the CRC-32
                fread(&compressedSize, sizeof (compressedSize), 1, file_); //Read the compressed size
                fread(&unCompressedSize, sizeof (unCompressedSize), 1, file_); // Read the uncompressed size
                fread(&size, sizeof (size), 1, file_); // read the size of the file name
                fread(&extraFieldLength, sizeof (extraFieldLength), 1, file_); // read the size of the extra field


                char* name = (char*) malloc(size + 1);
                fread(name, 1, size, file_); // Read the name of the file
                name[size] = 0;


                FileHeaderInfo* fileHeader = new FileHeaderInfo();
                fileHeader->setCompressedMethod(compressedMethod);
                fileHeader->setCompressedSize(compressedSize);
                fileHeader->setCRC(crc);
                fileHeader->setExtraFieldLength(extraFieldLength);
                fileHeader->setFileFullPathName(name);
                fileHeader->setFlag(flag);
                fileHeader->setHeader(header);
                fileHeader->setSize(size);
                fileHeader->setUncompressedSize(unCompressedSize);

                if (compressedSize > 0)
                {
                    char* fileData = (char*) malloc(compressedSize + 1);
                    fseek(file_, extraFieldLength, SEEK_CUR);
                    fread(fileData, 1, compressedSize, file_);
                    fileData[compressedSize] = '\0';
                    fileHeader->setFileData(fileData);
                }
                fileHeadersList.add(fileHeader);

                count++;


            }
        }
        fclose(file_);
        return fileHeadersList;
    }


